package mylog

import (
	"fmt"
	"os"
	"strings"
	"sync"
	"time"
)

func init() {
	// init setting
}

type (
	Log struct {
		MsgPrefix       string
		DepthInfo       []Info
		Depth           int
		FuncName        string
		StartMsgPrefix  string
		EndMsgPrefix    string
		IndentMsg       string
		PrefixIndentMsg string
		IgnoreFuncs     map[string]bool
		Lock            sync.RWMutex
		Id              string
	}
)

type Info struct {
	FuncName string
	Msg      string
}

func NewLogger(id string, from *Log) *Log {
	if from == nil {
		from = Logger
	}
	id = fmt.Sprintf("%v_%v", id, time.Now().UnixMicro())
	// newLog := *from
	newLog := DefaultLogger()
	newLog.CopyNew(from)
	newLog.Id = fmt.Sprintf("%v ,from_%v_%v", id, (*from).FuncName, (*from).Id)
	return newLog
}

func (l *Log) CopyNew(f *Log) *Log {
	l.Depth = f.Depth
	l.DepthInfo = f.DepthInfo
	l.FuncName = f.FuncName
	l.Id = f.Id
	l.IgnoreFuncs = f.IgnoreFuncs
	l.IndentMsg = f.IndentMsg
	l.EndMsgPrefix = f.EndMsgPrefix
	l.MsgPrefix = f.MsgPrefix
	l.PrefixIndentMsg = f.PrefixIndentMsg
	l.StartMsgPrefix = f.StartMsgPrefix
	l.Lock = sync.RWMutex{}
	return l
}

func (log *Log) NewLogger(id string) *Log {
	return NewLogger(id, log)
}

var Logger *Log

var Location *time.Location

func DefaultLogger() *Log {
	return &Log{
		DepthInfo:       make([]Info, 0, 5),
		Depth:           0,
		MsgPrefix:       "**    ",
		StartMsgPrefix:  "** >  ",
		EndMsgPrefix:    "** <  ",
		IndentMsg:       "  .  ",
		PrefixIndentMsg: "     ",
		// IgnoreList:      make(map[string]bool),
		IgnoreFuncs: map[string]bool{},
		Lock:        sync.RWMutex{},
		// Id:          fmt.Sprintf("%s", time.Now()),

		Id:       time.Now().In(Location).String(),
		FuncName: "default_main",
	}
}

func init() {
	if l, err := time.LoadLocation("Asia/Shanghai"); err == nil {
		Location = l
	} else {
		panic(err)
	}

	Logger = DefaultLogger()

	ignoreFuncs := os.Getenv("ignore_funcs")
	if ignoreFuncs == "" {
		println("[ logger.Info ], you can set environment var to ignore_funcs output, such as  [ export ignore_funcs=add,sum,main ]")
		return
	}

	funcs := strings.Split(ignoreFuncs, ",")
	for _, funcname := range funcs {
		Logger.IgnoreFuncs[funcname] = true
		println("[ logger.warring ], log will ignore func:[", funcname, "]")
	}
}

func (logger *Log) MyPrintf(format string, args ...interface{}) {
	// println("funaname:", logger.FuncName, logger.DepthInfo, logger.Depth)
	if logger.IgnoreFuncs[logger.FuncName] {
		//		println(logger.FuncName, "is in ignore list")
		return
	}
	fmt.Printf(format, args...)

	// logger2.Infof(format, args...)
	// logger2.GetLogger().WithField("info").Infof(format, args...)
	// logger2.GetLogger().WithField("mode", "mylog").Errorf(format, args...)
}

func (logger *Log) Start(name, msg string) {
	logger.Lock.Lock()
	defer logger.Lock.Unlock()
	logger.FuncName = name
	logger.Depth += 1
	logger.DepthInfo = append(logger.DepthInfo, Info{
		FuncName: name,
		Msg:      msg,
	})
	logger.MyPrintf("\n\n%s -> %v func %s: [ %s ] ,id: %s\n\n", logger.StartMsgPrefix, logger.Depth, name, msg, logger.Id)
	logger.MsgPrefix = logger.PrefixIndentMsg + logger.MsgPrefix
	// logger.StartMsgPrefix += " . "
	logger.StartMsgPrefix += logger.IndentMsg
	logger.EndMsgPrefix += logger.IndentMsg
}

func (logger *Log) Startln(msg ...interface{}) {
	Msg := ""
	Name := ""
	for i, msg := range msg {
		if i > 0 {
			Msg += fmt.Sprintf("%v ", msg)
		} else {
			Name = fmt.Sprintf("%v", msg)
		}
	}
	logger.Start(Name, Msg)
}

func (logger *Log) Startf(name, format string, msg ...interface{}) {
	Name := name
	Msg := fmt.Sprintf(format, msg...)
	logger.Start(Name, Msg)
}

func (logger *Log) Printf(format string, msg ...interface{}) {
	logger.Lock.RLock()
	logger.MyPrintf("\n%s [ ", logger.MsgPrefix)
	id := logger.Id
	logger.Lock.RUnlock()
	logger.MyPrintf(format, msg...)
	logger.MyPrintf(" ] ,id: %s\n", id)
}

func (logger *Log) Println(msg ...interface{}) {
	logger.Lock.RLock()
	Msg := logger.MsgPrefix + " [ "
	id := logger.Id
	logger.Lock.RUnlock()

	for _, m := range msg {
		Msg += fmt.Sprintf("%v ", m)
	}
	logger.MyPrintf("\n%s ] ,id: %s\n", Msg, id)
}

// args: 函数名， 信息
func (logger *Log) End(msg string) (err error) {
	logger.Lock.Lock()
	defer logger.Lock.Unlock()
	// println("*****debug,", logger.FuncName, logger.Depth, logger.DepthInfo)
	err = fmt.Errorf("%s", msg)
	if logger.Depth > 0 {
		logger.Depth -= 1
	} else {
		return
	}

	// 更新前缀信息
	logger.MsgPrefix = logger.MsgPrefix[len(logger.PrefixIndentMsg):len(logger.MsgPrefix)]
	logger.StartMsgPrefix = logger.StartMsgPrefix[:len(logger.EndMsgPrefix)-len(logger.IndentMsg)]
	logger.EndMsgPrefix = logger.EndMsgPrefix[:len(logger.EndMsgPrefix)-len(logger.IndentMsg)]
	logger.MyPrintf("\n\n%s<- %v endfunc %s: [ %s ] ,id: %s\n\n", logger.EndMsgPrefix, logger.Depth+1, logger.FuncName, msg, logger.Id)
	// 移除最后一个元素
	logger.DepthInfo = logger.DepthInfo[:logger.Depth]
	if logger.Depth > 0 {
		logger.FuncName = logger.DepthInfo[logger.Depth-1].FuncName
	} else {
		logger.FuncName = ""
	}
	// println("**************debug,", logger.FuncName, logger.Depth, logger.DepthInfo)
	return
}

func (logger *Log) Endf(format string, msg ...interface{}) error {
	Msg := fmt.Sprintf(format, msg...)
	return logger.End(Msg)
}

func (logger *Log) Endln(msg ...interface{}) error {
	Msg := ""
	for _, m := range msg {
		Msg += fmt.Sprintf("%v ", m)
	}
	return logger.End(Msg)
}

/*  效果如下
> -> func sign: sign a xxxx
*  v = 5
*  b = 4
> .-> func hash:
*   v= 5
*   b = 4
> ..-> func hash2:
*    v= 4
< ..<- hash2
< .<- hash
< <- sign
*/
